import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;

public class TcpToUdpForwarder {
    private final ServerConfiguration serverConfiguration;
    private final Logger logger;

    private final InetSocketAddress udpTarget;

    private final EventLoopGroup tcpBossGroup = new NioEventLoopGroup(1);
    private final EventLoopGroup tcpWorkerGroup = new NioEventLoopGroup();
    private final EventLoopGroup udpGroup = new NioEventLoopGroup();

    private Channel udpChannel;

    public TcpToUdpForwarder(ServerConfiguration serverConfiguration,
                             Logger logger
    ) {
        this.serverConfiguration = serverConfiguration;
        this.logger = logger;

        this.udpTarget = new InetSocketAddress(
                serverConfiguration.udp_host,
                serverConfiguration.udp_port
        );
    }

    public void start() throws InterruptedException {
        // 1. 启动 UDP Channel (仅用于发送)
        Bootstrap udpBootstrap = new Bootstrap();

        try {
            NetworkInterface ni = Utils.getInterfaceByCidr(serverConfiguration.getUdp_multicast_if());
            // 如果配置了multicast_if，则使用组播信息
            if (ni == null) {
                ni = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
            }
            udpBootstrap.group(udpGroup)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.IP_MULTICAST_IF, ni)
                    .handler(new ChannelInboundHandlerAdapter());
        }
        catch (Exception socketException)
        {
            throw new ServerException("[SERVER] Init local udp channel failed. ", socketException);
        }
        if (serverConfiguration.udp_local_port != 0) {
            udpChannel = udpBootstrap.bind(serverConfiguration.udp_local_port).sync().channel();
        }
        else
        {
            udpChannel = udpBootstrap.bind(0).sync().channel();
        }

        // 2. 启动 TCP Server
        ServerBootstrap tcpBootstrap = new ServerBootstrap();
        tcpBootstrap.group(tcpBossGroup, tcpWorkerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new SimpleChannelInboundHandler<io.netty.buffer.ByteBuf>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, io.netty.buffer.ByteBuf msg) {
                                // 复制收到的消息内容到数组
                                byte[] data = new byte[msg.readableBytes()];
                                msg.getBytes(msg.readerIndex(), data);

                                // 如果调试状态下打印收到的内容
                                if (logger.isTraceEnabled()) {
                                    for (String s : Utils.bytesToHexList(data)) {
                                        logger.trace(s);
                                    }
                                }

                                // 转发到 UDP
                                try {
                                    udpChannel.writeAndFlush(new DatagramPacket(
                                            Unpooled.wrappedBuffer(data),
                                            udpTarget
                                    )).sync();
                                }
                                catch (InterruptedException interruptedException)
                                {
                                    logger.error("[SERVER] 转发数据到目标[{}:{}]的转发链路被中断.",
                                            udpTarget.getAddress(), udpTarget.getPort(), interruptedException);
                                } catch (Exception e) {
                                    logger.error("[SERVER] 转发数据到目标到目标[{}:{}]的转发链路失败:",
                                            udpTarget.getAddress(), udpTarget.getPort(), e);
                                }
                            }
                        });
                    }
                });

        ChannelFuture future = tcpBootstrap.bind(serverConfiguration.tcp_port).sync();
        logger.info("[SERVER] Forwarder has opened at [{}:{}].",
                serverConfiguration.tcp_host,
                serverConfiguration.tcp_port);
        future.channel().closeFuture().sync();
    }

    public void stop() {
        tcpBossGroup.shutdownGracefully();
        tcpWorkerGroup.shutdownGracefully();
        udpGroup.shutdownGracefully();
    }
}
